/* Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "zlang_in.h"

static int InterpretStatement_finally( struct ZlangRuntime *rt , struct ZlangTokenDataUnitHeader *try_token_dataunit_header )
{
	struct ZlangTokenDataUnitHeader		*token_info5 = NULL ;
	char					*token5 = NULL ;
	int					nret = 0 ;
	
	if( try_token_dataunit_header->p7 && try_token_dataunit_header->p8 )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "enter try{ finally{ ... } }" )
		
		rt->travel_token_datapage_header = try_token_dataunit_header->p7 ;
		rt->travel_token_dataunit = try_token_dataunit_header->p8 ;
		TRAVELTOKEN_AND_SAVEINFO( rt , token_info5 , token5 )
		TRAVELTOKEN_AND_SAVEINFO( rt , token_info5 , token5 )
		if( token_info5->token_type != TOKEN_TYPE_BEGIN_OF_STATEMENT_SEGMENT ) /* { */
		{
			SET_RUNTIME_ERROR( rt , RUNTIME_ERROR , ZLANG_ERROR_SYNTAX , "expect '{' but '%s'" , rt->travel_token )
			return ZLANG_ERROR_SYNTAX;
		}
		
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "CALL InterpretStatementSegment" )
		IncreaseStackFrame( rt , NULL );
		rt->in_func = NULL ;
		nret = InterpretStatementSegment( rt , NULL ) ;
		DecreaseStackFrame( rt );
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "InterpretStatementSegment return[%d]" , nret )
		if( nret == ZLANG_INFO_END_OF_STATEMENT_SEGMENT || nret == ZLANG_INFO_BREAK )
		{
			TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "leave try{ finally{ ... } }" )
			
			if( nret == ZLANG_INFO_BREAK )
				nret = ZLANG_INFO_END_OF_STATEMENT_SEGMENT;
		}
		else
		{
			TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "InterpretStatementSegment return[%d]" , nret )
			return nret;
		}
	}
	
	return 0;
}

int InterpretStatement_try( struct ZlangRuntime *rt , struct ZlangInterpretStatementSegmentContext *interp_stat_seg_ctx )
{
	struct ZlangTokenDataUnitHeader		*try_token_dataunit_header = NULL ;
	struct ZlangTokenDataUnitHeader		*try_begin_of_statement_segment_token_info = NULL ;
	struct ZlangTokenDataUnitHeader		*token_info1 = NULL ;
	char					*token1 = NULL ;
	struct ZlangTokenDataUnitHeader		*token_info3 = NULL ;
	char					*token3 = NULL ;
	struct ZlangTokenDataUnitHeader		*token_info4 = NULL ;
	char					*token4 = NULL ;
	struct ZlangFunction			*bak_in_func = NULL ;
	int					nret = 0 ;
	int					nret2 = 0 ;
	
	TEST_RUNTIME_DEBUG_THEN_PRINT_ENTER_FUNCTION(rt)
	
	try_token_dataunit_header = rt->travel_token_info ;
	
	TRAVELTOKEN_AND_SAVEINFO( rt , token_info1 , token1 )
	if( token_info1->token_type != TOKEN_TYPE_BEGIN_OF_STATEMENT_SEGMENT ) /* { */
	{
		SET_RUNTIME_ERROR( rt , RUNTIME_ERROR , ZLANG_ERROR_SYNTAX , "expect '{' but '%s'" , rt->travel_token )
		TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
		return ZLANG_ERROR_SYNTAX;
	}
	
	try_begin_of_statement_segment_token_info = token_info1 ;
	
	TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "enter try{ ... }" )
	
	TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "CALL InterpretStatementSegment" )
	IncreaseStackFrame( rt , NULL );
	SetLocalObjectsStackFrameInTry( rt );
	bak_in_func = rt->in_func ;
	rt->in_func = NULL ;
	nret = InterpretStatementSegment( rt , NULL ) ;
	TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "InterpretStatementSegment return[%d]" , nret )
	if( nret == ZLANG_ERROR_INVOKE_METHOD_RETURN || nret == ZLANG_INFO_END_OF_STATEMENT_SEGMENT || nret == ZLANG_INFO_BREAK || nret == ZLANG_INFO_RETURN || nret == ZLANG_INFO_EXIT )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "leave try{ }" )
		
		if( nret == ZLANG_INFO_BREAK )
			nret = ZLANG_INFO_END_OF_STATEMENT_SEGMENT;
		
		nret2 = InterpretStatement_finally( rt , try_token_dataunit_header ) ;
		if( nret2 )
		{
			rt->in_func = bak_in_func ;
			DecreaseStackFrame( rt );
			TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
			return nret2;
		}
		
		rt->in_func = bak_in_func ;
		DecreaseStackFrame( rt );
		TEST_RUNTIME_DEBUG_THEN_PRINT_LEAVE_FUNCTION(rt)
		return nret;
	}
	else if( nret == ZLANG_INFO_THROW )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "throw from try{ ... }" )
		
		if( try_token_dataunit_header->p1 == NULL )
		{
			TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "expect catch in try{ ... }" )
			
			nret = InterpretStatement_finally( rt , try_token_dataunit_header ) ;
			if( nret )
			{
				rt->in_func = bak_in_func ;
				DecreaseStackFrame( rt );
				TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
				return nret;
			}
			
			rt->in_func = bak_in_func ;
			DecreaseStackFrame( rt );
			TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
			return ZLANG_INFO_THROW;
		}
		else if( HaveErrorException( rt ) )
		{
			TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "catch a error exception in try{ ... }" )
			
			rt->travel_token_datapage_header = try_token_dataunit_header->p1 ;
			rt->travel_token_dataunit = try_token_dataunit_header->p2 ;
			TRAVELTOKEN_AND_SAVEINFO( rt , token_info3 , token3 )
			
			CleanErrorException( rt );
			
			TRAVELTOKEN_AND_SAVEINFO( rt , token_info4 , token4 )
			if( token_info4->token_type != TOKEN_TYPE_BEGIN_OF_STATEMENT_SEGMENT ) /* { */
			{
				SET_RUNTIME_ERROR( rt , RUNTIME_ERROR , ZLANG_ERROR_SYNTAX , "expect '{' but '%s'" , rt->travel_token )
				
				rt->in_func = bak_in_func ;
				DecreaseStackFrame( rt );
				TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
				return ZLANG_ERROR_SYNTAX;
			}
			
			TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "CALL InterpretStatementSegment" )
			IncreaseStackFrame( rt , NULL );
			rt->in_func = NULL ;
			nret = InterpretStatementSegment( rt , NULL ) ;
			DecreaseStackFrame( rt );
			TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "InterpretStatementSegment return[%d]" , nret )
			if( nret == ZLANG_INFO_END_OF_STATEMENT_SEGMENT || nret == ZLANG_INFO_BREAK )
			{
				TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "leave catch{ ... }" )
				
				if( nret == ZLANG_INFO_BREAK )
					nret = ZLANG_INFO_END_OF_STATEMENT_SEGMENT;
				
				nret = InterpretStatement_finally( rt , try_token_dataunit_header ) ;
				if( nret )
				{
					rt->in_func = bak_in_func ;
					DecreaseStackFrame( rt );
					TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
					return nret;
				}
			}
			else
			{
				TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "InterpretStatementSegment return[%d]" , nret )
				rt->in_func = bak_in_func ;
				DecreaseStackFrame( rt );
				TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
				return nret;
			}
			
			rt->travel_token_datapage_header = try_begin_of_statement_segment_token_info->p1 ;
			rt->travel_token_dataunit = try_begin_of_statement_segment_token_info->p2 ;
			NEXTTOKEN( rt )
			
			rt->in_func = bak_in_func ;
			DecreaseStackFrame( rt );
			TEST_RUNTIME_DEBUG_THEN_PRINT_LEAVE_FUNCTION(rt)
			return ZLANG_INFO_END_OF_STATEMENT;
		}
		else if( HaveFatalException( rt ) )
		{
			TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "catch a fatal exception in try{ ... }" )
			
			nret = InterpretStatement_finally( rt , try_token_dataunit_header ) ;
			if( nret )
			{
				rt->in_func = bak_in_func ;
				DecreaseStackFrame( rt );
				TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
				return nret;
			}
			
			rt->in_func = bak_in_func ;
			DecreaseStackFrame( rt );
			TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
			return ZLANG_INFO_THROW;
		}
		else
		{
			TEST_RUNTIME_DEBUG_THEN_PRINT( rt , "unexpect process after throw in try{ ... }" )
			TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
			return ZLANG_ERROR_INTERNAL;
		}
	}
	else
	{
		SET_RUNTIME_ERROR( rt , RUNTIME_ERROR , ZLANG_ERROR_SYNTAX , "unexpect '%s'" , rt->travel_token )
		TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
		return ZLANG_ERROR_SYNTAX;
	}
}

int SkipStatement_try( struct ZlangRuntime *rt )
{
	int				nret = 0 ;
	
	TEST_RUNTIME_DEBUG_THEN_PRINT_ENTER_FUNCTION(rt)
	
	nret = SkipStatementSegment( rt ) ;
	if( nret != ZLANG_INFO_END_OF_STATEMENT_SEGMENT )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
		return nret;
	}
	
	TEST_RUNTIME_DEBUG_THEN_PRINT_LEAVE_FUNCTION(rt)
	return ZLANG_INFO_END_OF_STATEMENT;
}

int SkipStatement_catch( struct ZlangRuntime *rt )
{
	struct ZlangTokenDataUnitHeader	*token_info2 = NULL ;
	char				*token2 = NULL ;
	
	int				nret = 0 ;
	
	TEST_RUNTIME_DEBUG_THEN_PRINT_ENTER_FUNCTION(rt)
	
	TRAVELTOKEN_AND_SAVEINFO( rt , token_info2 , token2 )
	if( token_info2->token_type != TOKEN_TYPE_BEGIN_OF_STATEMENT_SEGMENT ) /* { */
	{
		SET_RUNTIME_ERROR( rt , RUNTIME_ERROR , ZLANG_ERROR_SYNTAX , "expect '{' but '%s'" , rt->travel_token )
		TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
		return ZLANG_ERROR_SYNTAX;
	}
	
	nret = SkipStatementSegment( rt ) ;
	if( nret != ZLANG_INFO_END_OF_STATEMENT_SEGMENT )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
		return nret;
	}
	
	TEST_RUNTIME_DEBUG_THEN_PRINT_LEAVE_FUNCTION(rt)
	return ZLANG_INFO_END_OF_STATEMENT;
}

int SkipStatement_finally( struct ZlangRuntime *rt )
{
	struct ZlangTokenDataUnitHeader	*token_info2 = NULL ;
	char				*token2 = NULL ;
	
	int				nret = 0 ;
	
	TEST_RUNTIME_DEBUG_THEN_PRINT_ENTER_FUNCTION(rt)
	
	TRAVELTOKEN_AND_SAVEINFO( rt , token_info2 , token2 )
	if( token_info2->token_type != TOKEN_TYPE_BEGIN_OF_STATEMENT_SEGMENT ) /* { */
	{
		SET_RUNTIME_ERROR( rt , RUNTIME_ERROR , ZLANG_ERROR_SYNTAX , "expect '{' but '%s'" , rt->travel_token )
		TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
		return ZLANG_ERROR_SYNTAX;
	}
	
	nret = SkipStatementSegment( rt ) ;
	if( nret != ZLANG_INFO_END_OF_STATEMENT_SEGMENT )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
		return nret;
	}
	
	TEST_RUNTIME_DEBUG_THEN_PRINT_LEAVE_FUNCTION(rt)
	return ZLANG_INFO_END_OF_STATEMENT;
}

int CheckStatement_try( struct ZlangRuntime *rt )
{
	struct ZlangTokenDataUnitHeader	*token_info1 = NULL ;
	char				*token1 = NULL ;
	
	int				nret = 0 ;
	
	TEST_RUNTIME_DEBUG_THEN_PRINT_ENTER_FUNCTION(rt)
	
	TRAVELTOKEN_AND_SAVEINFO( rt , token_info1 , token1 )
	if( token_info1->token_type != TOKEN_TYPE_BEGIN_OF_STATEMENT_SEGMENT ) /* { */
	{
		SET_RUNTIME_ERROR( rt , RUNTIME_ERROR , ZLANG_ERROR_SYNTAX , "expect '{' but '%s'" , rt->travel_token )
		TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
		return ZLANG_ERROR_SYNTAX;
	}
	
	IncreaseStackFrame( rt , NULL );
	rt->in_func = NULL ;
	nret = InterpretStatementSegment( rt , NULL ) ;
	DecreaseStackFrame( rt );
	if( nret != ZLANG_INFO_END_OF_STATEMENT_SEGMENT )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
		return nret;
	}
	
	TEST_RUNTIME_DEBUG_THEN_PRINT_LEAVE_FUNCTION(rt)
	return ZLANG_INFO_END_OF_STATEMENT;
}

int CheckStatement_catch( struct ZlangRuntime *rt )
{
	struct ZlangTokenDataUnitHeader	*token_info2 = NULL ;
	char				*token2 = NULL ;
	
	int				nret = 0 ;
	
	TEST_RUNTIME_DEBUG_THEN_PRINT_ENTER_FUNCTION(rt)
	
	TRAVELTOKEN_AND_SAVEINFO( rt , token_info2 , token2 )
	if( token_info2->token_type != TOKEN_TYPE_BEGIN_OF_STATEMENT_SEGMENT ) /* { */
	{
		SET_RUNTIME_ERROR( rt , RUNTIME_ERROR , ZLANG_ERROR_SYNTAX , "expect '{' but '%s'" , rt->travel_token )
		TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
		return ZLANG_ERROR_SYNTAX;
	}
	
	IncreaseStackFrame( rt , NULL );
	rt->in_func = NULL ;
	nret = InterpretStatementSegment( rt , NULL ) ;
	DecreaseStackFrame( rt );
	if( nret != ZLANG_INFO_END_OF_STATEMENT_SEGMENT )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
		return nret;
	}
	
	TEST_RUNTIME_DEBUG_THEN_PRINT_LEAVE_FUNCTION(rt)
	return ZLANG_INFO_END_OF_STATEMENT;
}

int CheckStatement_finally( struct ZlangRuntime *rt )
{
	struct ZlangTokenDataUnitHeader	*token_info2 = NULL ;
	char				*token2 = NULL ;
	
	int				nret = 0 ;
	
	TEST_RUNTIME_DEBUG_THEN_PRINT_ENTER_FUNCTION(rt)
	
	TRAVELTOKEN_AND_SAVEINFO( rt , token_info2 , token2 )
	if( token_info2->token_type != TOKEN_TYPE_BEGIN_OF_STATEMENT_SEGMENT ) /* { */
	{
		SET_RUNTIME_ERROR( rt , RUNTIME_ERROR , ZLANG_ERROR_SYNTAX , "expect '{' but '%s'" , rt->travel_token )
		TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
		return ZLANG_ERROR_SYNTAX;
	}
	
	IncreaseStackFrame( rt , NULL );
	rt->in_func = NULL ;
	nret = InterpretStatementSegment( rt , NULL ) ;
	DecreaseStackFrame( rt );
	if( nret != ZLANG_INFO_END_OF_STATEMENT_SEGMENT )
	{
		TEST_RUNTIME_DEBUG_THEN_PRINT_INTERRUPT_FUNCTION(rt)
		return nret;
	}
	
	TEST_RUNTIME_DEBUG_THEN_PRINT_LEAVE_FUNCTION(rt)
	return ZLANG_INFO_END_OF_STATEMENT;
}

